#include <gst/gst.h>
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>

// 前向声明所有函数，解决"was not declared"错误
typedef struct AppData AppData;
static void on_pad_added(GstElement *src, GstPad *new_pad, GstElement *rtph264depay);
static gboolean reconnect_callback(gpointer data);
static gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data);
static gboolean init_pipeline();

// 定义结构体
typedef struct AppData {
    GstElement *pipeline;
    GstElement *rtspsrc;
    GstElement *rtph264depay;
    GstElement *h264parse;
    GstElement *flvmux;
    GstElement *rtmpsink;
    GMainLoop *loop;
    gboolean is_playing;
    char rtsp_url[256];
    char rtmp_url[256];
    guint reconnect_timer_id;
} AppData;

static AppData app_data;

//--------------------------------------------------
// 函数实现
//--------------------------------------------------

// 清理Pipeline
static void cleanup_pipeline() {
    if (app_data.pipeline) {
        gst_element_set_state(app_data.pipeline, GST_STATE_NULL);
        gst_object_unref(app_data.pipeline);
        app_data.pipeline = NULL;
    }
}

// 动态衬垫连接回调
static void on_pad_added(GstElement *src, GstPad *new_pad, GstElement *rtph264depay) {
    GstPad *sink_pad = gst_element_get_static_pad(rtph264depay, "sink");
    if (gst_pad_link(new_pad, sink_pad) != GST_PAD_LINK_OK) {
        g_warning("Failed to link dynamic pad!");
    }
    gst_object_unref(sink_pad);
}

// 总线消息处理
static gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data) {
    switch (GST_MESSAGE_TYPE(msg)) {
    case GST_MESSAGE_ERROR: {
        GError *err = NULL;
        gchar *debug = NULL;
        gst_message_parse_error(msg, &err, &debug);
        g_printerr("Error: %s\n", err->message);
        g_error_free(err);
        g_free(debug);

        if (app_data.is_playing) {
            app_data.is_playing = FALSE;
            cleanup_pipeline();
            app_data.reconnect_timer_id = g_timeout_add_seconds(5, (GSourceFunc)reconnect_callback, NULL);
        }
        break;
    }
    case GST_MESSAGE_EOS:
        g_print("End of stream. Reconnecting...\n");
        cleanup_pipeline();
        app_data.reconnect_timer_id = g_timeout_add_seconds(5, (GSourceFunc)reconnect_callback, NULL);
        break;
    default:
        break;
    }
    return TRUE;
}

// 重连回调
static gboolean reconnect_callback(gpointer data) {
    if (init_pipeline()) {
        GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(app_data.pipeline));
        gst_bus_add_watch(bus, bus_callback, NULL);
        gst_object_unref(bus);
        gst_element_set_state(app_data.pipeline, GST_STATE_PLAYING);
        app_data.is_playing = TRUE;
        app_data.reconnect_timer_id = 0;
        printf("Reconnect success\n");
        return G_SOURCE_REMOVE;
    } else {
        g_printerr("Reconnect failed. Retrying...\n");
        return G_SOURCE_CONTINUE;
    }
}

// 初始化Pipeline
static gboolean init_pipeline() {
    app_data.pipeline = gst_pipeline_new("rtsp-to-rtmp");
    app_data.rtspsrc = gst_element_factory_make("rtspsrc", "rtspsrc");
    app_data.rtph264depay = gst_element_factory_make("rtph264depay", "rtph264depay");
    app_data.h264parse = gst_element_factory_make("h264parse", "h264parse");
    app_data.flvmux = gst_element_factory_make("flvmux", "flvmux");
    app_data.rtmpsink = gst_element_factory_make("rtmpsink", "rtmpsink");

    if (!app_data.pipeline || !app_data.rtspsrc || !app_data.rtph264depay ||
            !app_data.h264parse || !app_data.flvmux || !app_data.rtmpsink) {
        g_printerr("Failed to create elements\n");
        return FALSE;
    }

    // 设置属性
    g_object_set(app_data.rtspsrc,
                 "location", app_data.rtsp_url,
                 "drop-on-latency", TRUE,
                 "use-pipeline-clock", TRUE,
                 "do-retransmission", FALSE,
                 "latency", 0,
                 NULL);
    g_object_set(app_data.rtmpsink, "location", app_data.rtmp_url, NULL);

    // 添加元素到Pipeline
    gst_bin_add_many(GST_BIN(app_data.pipeline),
                     app_data.rtspsrc,
                     app_data.rtph264depay,
                     app_data.h264parse,
                     app_data.flvmux,
                     app_data.rtmpsink,
                     NULL);

    // 链接静态元素
    if (!gst_element_link_many(
                app_data.rtph264depay,
                app_data.h264parse,
                app_data.flvmux,
                app_data.rtmpsink,
                NULL)) {
        g_printerr("Failed to link elements\n");
        cleanup_pipeline();
        return FALSE;
    }

    // 动态链接rtspsrc的pad
    g_signal_connect(app_data.rtspsrc, "pad-added", G_CALLBACK(on_pad_added), app_data.rtph264depay);
    return TRUE;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        g_printerr("Usage: %s <RTSP_URL> <RTMP_URL>\n", argv[0]);
        return -1;
    }

    snprintf(app_data.rtsp_url, sizeof(app_data.rtsp_url), "%s", argv[1]);
    snprintf(app_data.rtmp_url, sizeof(app_data.rtmp_url), "%s", argv[2]);
    app_data.is_playing = FALSE;
    app_data.reconnect_timer_id = 0;

    gst_init(&argc, &argv);

    if (init_pipeline()) {
        GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(app_data.pipeline));
        gst_bus_add_watch(bus, bus_callback, NULL);
        gst_object_unref(bus);
        gst_element_set_state(app_data.pipeline, GST_STATE_PLAYING);
        app_data.is_playing = TRUE;
        g_print("init pipeline success\n");
    }

    app_data.loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(app_data.loop);

    if (app_data.reconnect_timer_id > 0) {
        g_source_remove(app_data.reconnect_timer_id);
    }
    cleanup_pipeline();
    g_main_loop_unref(app_data.loop);

    return 0;
}

//直接连接场景
// typedef struct _GstDataStruct
// {
//     GstElement *pipeline;
//     GstElement *rtspsrc;
//     GstElement *rtph264depay;
//     GstElement *h264parse;
//     GstElement *flvmux;
//     GstElement *rtmpsink;
//     GstBus *bus;
//     guint bus_watch_id;
//     GMainLoop *loop;
// } GstDataStruct;

// static GstDataStruct GstData;
// static char rtsp_url[256] = {0};
// static char rtmp_url[256] = {0};

// gboolean bus_msg_call(GstBus *bus, GstMessage *msg, GstDataStruct *pGstData)
// {
//     gchar *debug;
//     GError *error;
//     GMainLoop *loop = pGstData->loop;

//     switch (GST_MESSAGE_TYPE(msg)) {
//     case GST_MESSAGE_EOS:
//         g_print("End of stream\n");
//         g_main_loop_quit(loop);
//         break;
//     case GST_MESSAGE_ERROR:
//         gst_message_parse_error(msg, &error, &debug);
//         g_printerr("Error: %s\n", error->message);
//         g_error_free(error);
//         g_free(debug);
//         g_main_loop_quit(loop);
//         break;
//     default:
//         break;
//     }
//     return TRUE;
// }
// // 动态衬垫连接回调
// static void on_pad_added(GstElement *src, GstPad *new_pad, GstElement *rtph264depay) {
//     GstPad *sink_pad = gst_element_get_static_pad(rtph264depay, "sink");
//     if (gst_pad_link(new_pad, sink_pad) != GST_PAD_LINK_OK) {
//         g_warning("Failed to link dynamic pad!");
//     }
//     gst_object_unref(sink_pad);
// }
// int main(int argc, char *argv[])
// {
//     if (argc != 3) {
//         g_printerr("Usage: %s <RTSP_URL> <RTMP_URL>\n", argv[0]);
//         g_printerr("Example: %s rtsp://192.168.137.232/rightcam rtmp://192.168.137.232/live/test\n", argv[0]);
//         return -1;
//     }

//     // 保留输入参数
//     snprintf(rtsp_url, sizeof(rtsp_url), "%s", argv[1]);
//     snprintf(rtmp_url, sizeof(rtmp_url), "%s", argv[2]);

//     gst_init(&argc, &argv);

//     // 创建GStreamer元素
//     GstData.pipeline = gst_pipeline_new("rtsp-to-rtmp");
//     GstData.rtspsrc = gst_element_factory_make("rtspsrc", "rtspsrc");
//     GstData.rtph264depay = gst_element_factory_make("rtph264depay", "rtph264depay");
//     GstData.h264parse = gst_element_factory_make("h264parse", "h264parse");
//     GstData.flvmux = gst_element_factory_make("flvmux", "flvmux");
//     GstData.rtmpsink = gst_element_factory_make("rtmpsink", "rtmpsink");

//     if (!GstData.pipeline || !GstData.rtspsrc || !GstData.rtph264depay ||
//             !GstData.h264parse || !GstData.flvmux || !GstData.rtmpsink) {
//         g_printerr("Failed to create elements\n");
//         return -1;
//     }

//     // 设置元素属性
//     g_object_set(GstData.rtspsrc,
//                  "location", rtsp_url,
//                  "drop-on-latency", TRUE,
//                  "use-pipeline-clock", TRUE,
//                  "do-retransmission", FALSE,
//                  "latency", 0,
//                  NULL);

//     g_object_set(GstData.rtmpsink, "location", rtmp_url, NULL);

//     // 添加元素到管道
//     gst_bin_add_many(GST_BIN(GstData.pipeline),
//                      GstData.rtspsrc,
//                      GstData.rtph264depay,
//                      GstData.h264parse,
//                      GstData.flvmux,
//                      GstData.rtmpsink,
//                      NULL);

//     // 链接元素
//     if (!gst_element_link_many(
//                 GstData.rtph264depay,
//                 GstData.h264parse,
//                 GstData.flvmux,
//                 GstData.rtmpsink,
//                 NULL)) {
//         g_printerr("Failed to link elements\n");
//         gst_object_unref(GstData.pipeline);
//         return -1;
//     }
//     g_signal_connect(GstData.rtspsrc, "pad-added", G_CALLBACK(on_pad_added), GstData.rtph264depay);
//     // 总线消息监听
//     GstData.bus = gst_pipeline_get_bus(GST_PIPELINE(GstData.pipeline));
//     GstData.bus_watch_id = gst_bus_add_watch(GstData.bus, (GstBusFunc)bus_msg_call, &GstData);
//     gst_object_unref(GstData.bus);

//     // 启动管道
//     gst_element_set_state(GstData.pipeline, GST_STATE_PLAYING);
//     GstData.loop = g_main_loop_new(NULL, FALSE);
//     g_main_loop_run(GstData.loop);

//     // 清理资源
//     gst_element_set_state(GstData.pipeline, GST_STATE_NULL);
//     gst_object_unref(GstData.pipeline);
//     g_source_remove(GstData.bus_watch_id);
//     g_main_loop_unref(GstData.loop);

//     return 0;
// }